package com.yociyy.config;

import com.yociyy.security.authentication.YoCiUser;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.provider.code.AuthorizationCodeServices;
import org.springframework.security.oauth2.provider.code.InMemoryAuthorizationCodeServices;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;

import java.util.Collection;
import java.util.HashSet;
import java.util.Set;

/**
 * security 安全相关配置类
 * 
 * @author: YoCiyy
 * @date: 2020/6/22
 */
@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

	/**
	 * 安全拦截机制
	 */
	@Override
	protected void configure(HttpSecurity http) throws Exception {
		http
				.authorizeRequests()
				// 放行
				.antMatchers("/auth/**")
				.permitAll()
				// 其他请求必须认证通过
				.anyRequest().authenticated()
				.and()
				.formLogin() // 允许表单登录
				// .successForwardUrl("/login-success") //自定义登录成功跳转页
				.and()
				.csrf().disable();

	}

	/**
	 * token持久化配置
	 */
	// @Bean
	// public TokenStore tokenStore() {
	// // 本地内存存储令牌
	// return new InMemoryTokenStore();
	// }

	/**
	 * 密码加密器
	 */
	@Bean
	public PasswordEncoder passwordEncoder() {
		return new BCryptPasswordEncoder();
	}

	/**
	 * 认证管理器配置
	 */
	@Bean
	@Override
	protected AuthenticationManager authenticationManager() {
		return authentication -> daoAuthenticationProvider().authenticate(authentication);
	}

	/**
	 * 认证是由 AuthenticationManager 来管理的，但是真正进行认证的是 AuthenticationManager 中定义的 AuthenticationProvider，用于调用userDetailsService进行验证
	 */
	@Bean
	public AuthenticationProvider daoAuthenticationProvider() {
		DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider();
		daoAuthenticationProvider.setUserDetailsService(userDetailsService());
		daoAuthenticationProvider.setHideUserNotFoundExceptions(false);
		daoAuthenticationProvider.setPasswordEncoder(passwordEncoder());
		return daoAuthenticationProvider;
	}

	/**
	 * 用户详情服务
	 */
	@Bean
	@Override
	protected UserDetailsService userDetailsService() {
		// 测试方便采用内存存取方式
		InMemoryUserDetailsManager userDetailsService = new InMemoryUserDetailsManager();
		Collection<? extends GrantedAuthority> authorities
				= AuthorityUtils.createAuthorityList("ROLE_USER");
		Set<String> permissions = new HashSet<>();
		permissions.add("sys:user:admin");
		YoCiUser yoCiUser = new YoCiUser(1L, 1L, permissions, "user_1", passwordEncoder().encode("123456"), true, true, true, true, authorities);
		userDetailsService.createUser(yoCiUser);
		// userDetailsService.createUser(User.withUsername("user_1").password(passwordEncoder().encode("123456")).authorities("ROLE_USER").build());
//		userDetailsService.createUser(User.withUsername("user_2").password(passwordEncoder().encode("1234567")).authorities("ROLE_USER").build());
		return new UserDetailBiz(passwordEncoder());
	}

	/**
	 * 设置授权码模式的授权码如何存取，暂时采用内存方式 
	 */
	@Bean
	public AuthorizationCodeServices authorizationCodeServices() {
		return new InMemoryAuthorizationCodeServices();
	}

	/**
	 * jwt token解析器
	 */
	// @Bean
	// public JwtAccessTokenConverter accessTokenConverter() {
	//
	// JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
	// // 对称密钥，资源服务器使用该密钥来验证
	// converter.setSigningKey("YoCiyy");
	// return converter;
	// }
}
